//
// FileControlBlock.cpp
// Usage: Process FCB
// CreateDate: 2009-05-19
// Author: MaJiuyue
//
#include <unistd.h>
#include <SCI.h>
#include "FileControlBlock.h"

FileControlBlock::FileControlBlock()
{
	m_RootDir = NULL;
	m_WorkingDir = NULL;
	m_OpenFileNR = 0;
	for(int i=0; i<MAX_OPENFILE_NR; i++)
	{
		m_FileObjectTable[i].f_fd = NULL;
		m_FileObjectTable[i].f_pos = 0;
	}
}

FileControlBlock::FileControlBlock(const FileControlBlock &target)
{
	kprintf("FileControlBlock::FileControlBlock() copy construct need fix.\n");
	return;
	m_RootDir = target.m_RootDir;
	m_RootDir->open();
 	m_WorkingDir = target.m_WorkingDir;
	m_WorkingDir->open();
	m_OpenFileNR = target.m_OpenFileNR;
	for(int i=0; i<MAX_OPENFILE_NR; i++)
	{
		m_FileObjectTable[i].f_fd = target.m_FileObjectTable[i].f_fd;
		m_FileObjectTable[i].f_pos = target.m_FileObjectTable[i].f_pos;
		if(m_FileObjectTable[i].f_fd != NULL)
			m_FileObjectTable[i].f_fd->open();
	}
}

FileControlBlock::~FileControlBlock()
{
	for(int i=0; i<MAX_OPENFILE_NR; i++)
		if(m_FileObjectTable[i].f_fd!=NULL)
			m_FileObjectTable[i].f_fd->close();
	m_RootDir->close();
	m_WorkingDir->close();
}

int FileControlBlock::open(const char * path)
{
	// Too many open file
	if(m_OpenFileNR>MAX_OPENFILE_NR)
		return -EMFILE;

	Resource * res = ResourceManager.RequestResource(
		ServiceCallInterface::FileSystem::ResourceName
	);
	File * fd = (File *)res->CallSCI(
		ServiceCallInterface::FileSystem::SCIID_GetFile,
		(u32)path
	);

	if( fd==NULL )
		return -ENOENT;

	// Find an empty fd
	for(int index=0; index<MAX_OPENFILE_NR; index++)
	{
		if(m_FileObjectTable[index].f_fd==NULL)
		{
			// open it
			m_FileObjectTable[index].f_fd = fd;
			m_FileObjectTable[index].f_pos = 0;
			m_OpenFileNR++;

			// Return fd
			return index;
		}
	}

	return -EMFILE;
}

void FileControlBlock::close(int fd)
{
	File * file = m_FileObjectTable[fd].f_fd;

	// if selected file not opened, just return
	if(file == NULL)
		return;

	// Close file
	file->close();
	// Free FileObjectTable
	file = NULL;
	// Opened file decrease
	m_OpenFileNR--;
}

int FileControlBlock::read(int fd, addr_t buf, size_t len)
{
	FileObject * fobject = &m_FileObjectTable[fd];
	int nsize = 0;

	// if selected file not opened, just ENOENT
	if(fobject->f_fd==NULL)
		return ENOENT;

	// do read
	nsize = fobject->f_fd->read(fobject->f_pos, len, buf);

	// if success, increase f_pos
	if(nsize>0)
		fobject->f_pos += nsize;

	return nsize;
}

int FileControlBlock::write(int fd, addr_t buf, size_t len)
{
	FileObject * fobject = &m_FileObjectTable[fd];
	int nsize = 0;

	// if selected file not opened, just ENOENT
	if(fobject->f_fd==NULL)
		return ENOENT;

	// do write
	nsize = fobject->f_fd->write(fobject->f_pos, len, buf);

	// if success, increase f_pos
	if(nsize>0)
		fobject->f_pos += nsize;

	return nsize;
}

int FileControlBlock::lseek(int fd, int offset, int whence)
{
	if(m_FileObjectTable[fd].f_fd==NULL)
		return ENOENT;

	switch(whence)
	{
	case SEEK_SET:
		m_FileObjectTable[fd].f_pos = offset;
		break;
	case SEEK_CUR:
		m_FileObjectTable[fd].f_pos += offset;
		break;
	case SEEK_END:
		m_FileObjectTable[fd].f_pos = m_FileObjectTable[fd].f_fd->GetLength()+offset;
		break;
	default:
		return -1;
	}

	return m_FileObjectTable[fd].f_pos;
}

